package design._01_重温动态代理;

import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.apache.commons.lang3.StringUtils;
import sun.misc.ProxyGenerator;

import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class MainTest {
    static DuckDog duckDog = new DuckDog();
    static DuckDog duckDog2 = new DuckDog2();
    static Duck duck = new Duck();
    static Dog dog = new Dog();

    public static void main(String[] args) {

        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        // 1. JDK 动态代理
        //JDKProxy();
        // 1.1 打印类
        //printClass();

        // 2. cglib Proxy
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/Users/judy/workspace/test/2020/test_gradle/out/production/classes/design/_01_重温动态代理");
        cglibProxy();
    }

    static int num = 0;

    private static void cglibProxy() {
        Enhancer en = new Enhancer();
        en.setSuperclass(DuckDog.class);
        en.setCallbacks(new Callback[]{
            new MethodInterceptor() {
                @Override
                public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                    String name = method.getName();
                    if (name.equals("toString")) {
                        return "";
                    }
                    System.out.println(String.format("---invoke=%s----args=%s", name, Arrays.toString(args)));
                    if (StringUtils.containsIgnoreCase(name, "dog")) {
                        return method.invoke(duckDog2, args);
                    }
                    return method.invoke(duckDog, args);
                }
            }

        });
        DuckDog duck = (DuckDog) en.create();
        System.out.println(duck.getDuckName());
        System.out.println(duck.getDogName());
    }

    private static void JDKProxy() {
        ClassLoader classLoader = MainTest.class.getClassLoader();
        IDuck duck = (IDuck) Proxy.newProxyInstance(classLoader,
            DuckDog.class.getInterfaces(),
            getInvocationHandler());
        System.out.println(duck.getDuckName());
        IDog dog = (IDog) duck;
        System.out.println(dog.getDogName());
    }

    private static InvocationHandler getInvocationHandler() {
        return (proxy, method, args) -> {
            String name = method.getName();
            System.out.println(String.format("---invoke=%s----args=%s", name, Arrays.toString(args)));
            if (StringUtils.containsIgnoreCase(name, "dog")) {
                return method.invoke(dog, args);
            }
            return method.invoke(duck, args);
        };
    }

    private static void printClass() {
        byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", DuckDog.class.getInterfaces());

        try {
            FileOutputStream out = new FileOutputStream("/Users/judy/workspace/test/2020/test_gradle/out/production/classes/design/_01_重温动态代理/$Proxy0.class");
            out.write(classFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
